import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                           QHBoxLayout, QTextEdit, QMenuBar, QMenu, QAction,
                           QSplitter, QScrollBar, QMessageBox, QFileDialog,
                           QToolBar)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont, QIcon
from file_operations import FileOperations
from code_editor import CodeEditor

# 导入C语言词法分析器的Python包装器
try:
    # 尝试从lexer包中导入PyLexer
    from lexer import PyLexer
    print("成功导入PyLexer")
    C_LEXER_AVAILABLE = True
except ImportError as e:
    print(f"导入PyLexer失败: {e}")
    # 尝试从旧路径导入（兼容旧版本）
    try:
        from py_lexer import PyLexer
        print("成功从旧路径导入PyLexer")
        C_LEXER_AVAILABLE = True
    except ImportError as e:
        print(f"从旧路径导入PyLexer失败: {e}")
        C_LEXER_AVAILABLE = False

# 导入代码执行模块
try:
    from eval_excute import execute_code
    print("成功导入eval_excute模块")
    CODE_EVAL_AVAILABLE = True
except ImportError as e:
    print(f"导入eval_excute模块失败: {e}")
    CODE_EVAL_AVAILABLE = False

# 导入中间代码生成模块
try:
    from instruction_gen import generate_intermediate_code as gen_ir_code
    print("成功导入instruction_gen模块")
    INSTRUCTION_GEN_AVAILABLE = True
except ImportError as e:
    print(f"导入instruction_gen模块失败: {e}")
    INSTRUCTION_GEN_AVAILABLE = False

# 导入符号表打印模块
try:
    from symbol_print import generate_symbol_table as gen_symbol_table
    print("成功导入symbol_print模块")
    SYMBOL_PRINT_AVAILABLE = True
except ImportError as e:
    print(f"导入symbol_print模块失败: {e}")
    SYMBOL_PRINT_AVAILABLE = False

class CompilerIDE(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('compiler2025')
        self.resize(1000, 600)
        
        # 创建中心部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)
        
        # 创建菜单栏
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')
        
        # 添加文件菜单项
        open_file_action = QAction('打开文件', self)
        open_file_action.triggered.connect(self.open_file)
        file_menu.addAction(open_file_action)
        
        open_folder_action = QAction('打开文件夹', self)
        open_folder_action.triggered.connect(self.open_folder)
        file_menu.addAction(open_folder_action)
        
        # 添加移除工作区选项
        file_menu.addSeparator()  # 添加分隔线
        remove_workspace_action = QAction('移除工作区', self)
        remove_workspace_action.triggered.connect(self.remove_workspace)
        file_menu.addAction(remove_workspace_action)
        
        edit_menu = menubar.addMenu('编辑')
        lexical_menu = menubar.addMenu('词法分析')
        
        # 添加词法分析菜单项
        analyze_action = QAction('对当前文件进行词法分析', self)
        analyze_action.triggered.connect(self.analyze_current_file)
        lexical_menu.addAction(analyze_action)
        
        # 添加代码执行菜单
        execute_menu = menubar.addMenu('代码执行')
        
        # 添加代码执行菜单项
        execute_action = QAction('执行当前代码', self)
        execute_action.triggered.connect(self.execute_current_code)
        execute_menu.addAction(execute_action)
        
        # 添加语法分析菜单
        parser_menu = menubar.addMenu('语法分析')
        
        # 添加中间代码生成菜单项
        generate_ir_action = QAction('生成中间代码', self)
        generate_ir_action.triggered.connect(self.generate_intermediate_code)
        parser_menu.addAction(generate_ir_action)
        
        # 添加符号表打印菜单项
        generate_symbol_action = QAction('打印符号表', self)
        generate_symbol_action.triggered.connect(self.generate_symbol_table)
        parser_menu.addAction(generate_symbol_action)
        
        help_menu = menubar.addMenu('帮助')
        
        # 创建工具栏
        toolbar = QToolBar("主工具栏")
        self.addToolBar(toolbar)
        
        # 添加词法分析和代码执行按钮到工具栏
        analyze_tool_action = QAction('词法分析', self)
        analyze_tool_action.triggered.connect(self.analyze_current_file)
        # 如果有图标文件，可以设置图标
        # analyze_tool_action.setIcon(QIcon('path_to_icon.png'))
        toolbar.addAction(analyze_tool_action)
        
        # 添加代码执行按钮到工具栏
        execute_tool_action = QAction('执行代码', self)
        execute_tool_action.triggered.connect(self.execute_current_code)
        # 如果有图标文件，可以设置图标
        # execute_tool_action.setIcon(QIcon('path_to_icon.png'))
        toolbar.addAction(execute_tool_action)
        
        # 添加中间代码生成按钮到工具栏
        generate_ir_tool_action = QAction('中间代码', self)
        generate_ir_tool_action.triggered.connect(self.generate_intermediate_code)
        # 如果有图标文件，可以设置图标
        # generate_ir_tool_action.setIcon(QIcon('path_to_icon.png'))
        toolbar.addAction(generate_ir_tool_action)
        
        # 添加符号表打印按钮到工具栏
        generate_symbol_tool_action = QAction('符号表', self)
        generate_symbol_tool_action.triggered.connect(self.generate_symbol_table)
        # 如果有图标文件，可以设置图标
        # generate_symbol_tool_action.setIcon(QIcon('path_to_icon.png'))
        toolbar.addAction(generate_symbol_tool_action)
        
        # 创建主分割器
        main_splitter = QSplitter(Qt.Horizontal)
        
        # 初始化文件操作模块
        self.file_ops = FileOperations(self)
        
        # 创建编辑区域分割器
        edit_splitter = QSplitter(Qt.Horizontal)
        
        # 源代码输入区
        self.source_code = CodeEditor()
        self.source_code.setPlaceholderText('源代码输入区')
        
        # 中间结果显示区
        self.result_display = QTextEdit()
        self.result_display.setPlaceholderText('中间结果')
        self.result_display.setReadOnly(True)
        
        # 添加到编辑区域分割器
        edit_splitter.addWidget(self.source_code)
        edit_splitter.addWidget(self.result_display)
        
        # 添加到主分割器
        main_splitter.addWidget(self.file_ops.get_file_tree())
        main_splitter.addWidget(edit_splitter)
        
        # 设置分割器的初始大小
        main_splitter.setSizes([200, 800])
        
        # 错误信息显示区
        self.error_display = QTextEdit()
        self.error_display.setPlaceholderText('Error')
        self.error_display.setReadOnly(True)
        self.error_display.setMaximumHeight(150)
        
        # 添加到主布局
        layout.addWidget(main_splitter)
        layout.addWidget(self.error_display)
        
        # 连接文件树点击事件
        self.file_ops.file_tree.clicked.connect(self.on_file_clicked)
        
        # 初始化词法分析器
        global C_LEXER_AVAILABLE  # 声明使用全局变量
        if C_LEXER_AVAILABLE:
            try:
                print("正在初始化词法分析器...")
                # 导入并初始化词法分析器
                self.lexer = PyLexer() # 初始化词法分析器
                
                # 检查库文件路径
                if hasattr(self.lexer, "get_lib_path"):
                    lib_path = self.lexer.get_lib_path()
                    print(f"词法分析器库路径: {lib_path}")
                    if os.path.exists(lib_path):
                        print(f"库文件存在: {lib_path}")
                    else:
                        print(f"库文件不存在: {lib_path}")
                
                print("成功加载C语言词法分析器")
                self.error_display.setText("成功加载C语言词法分析器")
            except Exception as e:
                import traceback
                error_msg = f"无法加载C语言词法分析器: {str(e)}\n{traceback.format_exc()}"
                print(error_msg)
                self.error_display.setText(f"无法加载C语言词法分析器: {str(e)}")
                C_LEXER_AVAILABLE = False
        else:
            self.error_display.setText("C语言词法分析器不可用，请确保已编译clexer库")
        
        # 当前文件路径
        self.current_file_path = None
        
    def open_file(self):
        file_dialog = QFileDialog()
        file_path, _ = file_dialog.getOpenFileName(self, "打开文件", "", "所有文件 (*.*)")
        if file_path:
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    content = file.read()
                    self.source_code.setPlainText(content)
                    self.current_file_path = file_path
            except Exception as e:
                self.error_display.setText(f"打开文件错误: {str(e)}")
    
    def open_folder(self):
        self.file_ops.open_folder()
    
    def remove_workspace(self):
        if self.file_ops.remove_workspace():
            self.source_code.clear()
            self.error_display.setText("工作区已移除")
    
    # 点击文件夹中的文件触发
    def on_file_clicked(self, index):
        file_path = self.file_ops.file_model.data(index, Qt.UserRole)
        if os.path.isfile(file_path):
            try:
                with open(file_path, 'r', encoding='utf-8') as file:
                    content = file.read()
                    self.source_code.setPlainText(content)
                    self.current_file_path = file_path
            except Exception as e:
                self.error_display.setText(f"打开文件错误: {str(e)}")
    
    # 对当前文件进行词法分析
    def analyze_current_file(self):
        # 检查C语言词法分析器是否可用
        global C_LEXER_AVAILABLE  # 在这里也需要声明全局变量
        if not C_LEXER_AVAILABLE:
            reply = QMessageBox.question(
                self, 
                '确认编译', 
                'C语言词法分析器不可用，是否尝试编译clexer库?',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.Yes
            )
            if reply == QMessageBox.Yes:
                self.error_display.setText("正在尝试编译词法分析器...")
                try:
                    # 使用copy_lexer_lib模块确保库文件存在
                    from copy_lexer_lib import ensure_lexer_lib
                    if ensure_lexer_lib():
                        self.error_display.setText("编译成功，重新初始化词法分析器...")
                        try:
                            from lexer import PyLexer
                            self.lexer = PyLexer()
                            C_LEXER_AVAILABLE = True
                            self.error_display.setText("成功加载C语言词法分析器!")
                        except Exception as e:
                            import traceback
                            error_msg = f"加载失败: {str(e)}\n{traceback.format_exc()}"
                            self.error_display.setText(error_msg)
                            return
                    else:
                        self.error_display.setText("编译或确保库文件位置失败，无法使用词法分析器。")
                        return
                except Exception as e:
                    import traceback
                    error_msg = f"编译过程出错: {str(e)}\n{traceback.format_exc()}"
                    self.error_display.setText(error_msg)
                    return
            else:
                return
                
        # 获取源代码
        code = self.source_code.toPlainText()
        if not code:
            QMessageBox.warning(self, "词法分析", "当前没有代码可供分析！")
            return
        
        # 检查当前文件是否是C文件
        if self.current_file_path and not self.current_file_path.lower().endswith('.c'):
            reply = QMessageBox.question(
                self, 
                '确认分析', 
                '当前文件不是C文件，是否继续进行词法分析？',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.No
            )
            if reply == QMessageBox.No:
                return
        
        try:
            # 使用C语言词法分析器进行分析，获取结果和错误信息
            result, error = self.lexer.get_formatted_result_and_error(code)
            
            # 在结果区域显示分析结果
            self.result_display.setPlainText(result)
            
            # 在错误区域显示错误（如果有）
            if error:
                self.error_display.setText(f"词法分析错误: {error}")
            else:
                self.error_display.clear()
        except Exception as e:
            self.error_display.setText(f"词法分析错误: {str(e)}")
            
    # 执行当前代码
    def execute_current_code(self):
        global CODE_EVAL_AVAILABLE
        
        if not CODE_EVAL_AVAILABLE:
            self.error_display.setText("代码执行模块不可用，请确保已编译eval_excute库")
            return
        
        # 获取源代码
        code = self.source_code.toPlainText()
        if not code:
            QMessageBox.warning(self, "代码执行", "当前没有代码可供执行！")
            return
        
        # 检查当前文件是否是C文件
        if self.current_file_path and not self.current_file_path.lower().endswith('.c'):
            reply = QMessageBox.question(
                self, 
                '确认执行', 
                '当前文件不是C文件，是否继续执行？',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.No
            )
            if reply == QMessageBox.No:
                return
        
        try:
            self.error_display.setText("正在执行代码...")
            
            # 使用eval_excute模块的execute_code函数
            result = execute_code(code)
            
            if result:
                # 使用HTML格式优化显示
                html_result = "<div style='font-family: Consolas, Courier New, monospace;'>"
                html_result += "<h3 style='color: #0066cc;'>代码执行结果</h3>"
                
                # 对输出进行处理
                result_lines = result.splitlines()
                for line in result_lines:
                    # 检测是否是错误信息行
                    if "error" in line.lower() or "错误" in line:
                        html_result += f"<p style='color: #cc0000;'>{line}</p>"
                    # 检测是否是警告信息行    
                    elif "warning" in line.lower() or "警告" in line:
                        html_result += f"<p style='color: #ff9900;'>{line}</p>"
                    # 检测是否是成功信息行
                    elif "success" in line.lower() or "成功" in line:
                        html_result += f"<p style='color: #009900;'>{line}</p>"
                    # 普通输出行
                    else:
                        html_result += f"<p>{line}</p>"
                
                html_result += "</div>"
                
                # 在结果区域显示
                self.result_display.clear()
                self.result_display.setHtml(html_result)
                
                self.error_display.setText("代码执行完成")
            else:
                self.error_display.setText("代码执行失败：返回结果为空")
        except Exception as e:
            import traceback
            error_msg = f"代码执行错误: {str(e)}\n{traceback.format_exc()}"
            self.error_display.setText(error_msg)

    # 生成中间代码
    def generate_intermediate_code(self):
        global INSTRUCTION_GEN_AVAILABLE
        
        if not INSTRUCTION_GEN_AVAILABLE:
            self.error_display.setText("中间代码生成模块不可用，请确保instruction_gen.py和print_instruction_test.exe存在")
            return
        
        # 获取源代码
        code = self.source_code.toPlainText()
        if not code:
            QMessageBox.warning(self, "中间代码生成", "当前没有代码可供分析！")
            return
        
        # 检查当前文件是否是C文件
        if self.current_file_path and not self.current_file_path.lower().endswith('.c'):
            reply = QMessageBox.question(
                self, 
                '确认分析', 
                '当前文件不是C文件，是否继续进行中间代码生成？',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.No
            )
            if reply == QMessageBox.No:
                return
        
        try:
            self.error_display.setText("正在生成中间代码...")
            
            # 使用instruction_gen模块生成中间代码
            success, result, error_message = gen_ir_code(code)
            
            if success:
                # 生成成功
                if result:
                    # 使用HTML格式优化显示
                    html_result = "<div style='font-family: Consolas, Courier New, monospace;'>"
                    html_result += "<h3 style='color: #0066cc;'>中间代码生成结果</h3>"
                    
                    # 对输出进行处理
                    result_lines = result.splitlines()
                    for line in result_lines:
                        # 检测是否是错误信息行
                        if "error" in line.lower() or "错误" in line:
                            html_result += f"<p style='color: #cc0000;'>{line}</p>"
                        # 检测是否是警告信息行    
                        elif "warning" in line.lower() or "警告" in line:
                            html_result += f"<p style='color: #ff9900;'>{line}</p>"
                        # 检测是否是指令行（通常包含数字编号）
                        elif line.strip() and (line.strip()[0].isdigit() or line.strip().startswith("(")):
                            html_result += f"<p style='color: #006600;'>{line}</p>"
                        # 普通输出行
                        else:
                            html_result += f"<p>{line}</p>"
                    
                    html_result += "</div>"
                    
                    # 在结果区域显示
                    self.result_display.clear()
                    self.result_display.setHtml(html_result)
                    
                    self.error_display.setText("中间代码生成完成")
                else:
                    self.result_display.setPlainText("中间代码生成完成，但没有输出内容")
                    self.error_display.setText("中间代码生成完成")
            else:
                # 生成失败
                self.error_display.setText(f"中间代码生成失败: {error_message}")
                self.result_display.setPlainText(f"生成失败: {error_message}")
                
        except Exception as e:
            import traceback
            error_msg = f"中间代码生成错误: {str(e)}\n{traceback.format_exc()}"
            self.error_display.setText(error_msg)

    # 生成符号表
    def generate_symbol_table(self):
        global SYMBOL_PRINT_AVAILABLE
        
        if not SYMBOL_PRINT_AVAILABLE:
            self.error_display.setText("符号表打印模块不可用，请确保symbol_print.py和print_symbol_test.exe存在")
            return
        
        # 获取源代码
        code = self.source_code.toPlainText()
        if not code:
            QMessageBox.warning(self, "符号表生成", "当前没有代码可供分析！")
            return
        
        # 检查当前文件是否是C文件
        if self.current_file_path and not self.current_file_path.lower().endswith('.c'):
            reply = QMessageBox.question(
                self, 
                '确认分析', 
                '当前文件不是C文件，是否继续进行符号表生成？',
                QMessageBox.Yes | QMessageBox.No, 
                QMessageBox.No
            )
            if reply == QMessageBox.No:
                return
        
        try:
            self.error_display.setText("正在生成符号表...")
            
            # 使用symbol_print模块生成符号表
            success, result, error_message = gen_symbol_table(code)
            
            if success:
                # 生成成功
                if result:
                    # 使用HTML格式优化显示
                    html_result = "<div style='font-family: Consolas, Courier New, monospace;'>"
                    html_result += "<h3 style='color: #0066cc;'>符号表生成结果</h3>"
                    
                    # 对输出进行处理
                    result_lines = result.splitlines()
                    for line in result_lines:
                        # 检测是否是错误信息行
                        if "error" in line.lower() or "错误" in line:
                            html_result += f"<p style='color: #cc0000;'>{line}</p>"
                        # 检测是否是警告信息行    
                        elif "warning" in line.lower() or "警告" in line:
                            html_result += f"<p style='color: #ff9900;'>{line}</p>"
                        # 检测是否是符号表行（通常包含变量名、类型等）
                        elif line.strip() and ("Symbol" in line or "变量" in line or "函数" in line or "|" in line):
                            html_result += f"<p style='color: #006600;'>{line}</p>"
                        # 普通输出行
                        else:
                            html_result += f"<p>{line}</p>"
                    
                    html_result += "</div>"
                    
                    # 在结果区域显示
                    self.result_display.clear()
                    self.result_display.setHtml(html_result)
                    
                    self.error_display.setText("符号表生成完成")
                else:
                    self.result_display.setPlainText("符号表生成完成，但没有输出内容")
                    self.error_display.setText("符号表生成完成")
            else:
                # 生成失败
                self.error_display.setText(f"符号表生成失败: {error_message}")
                self.result_display.setPlainText(f"生成失败: {error_message}")
                
        except Exception as e:
            import traceback
            error_msg = f"符号表生成错误: {str(e)}\n{traceback.format_exc()}"
            self.error_display.setText(error_msg)

def main():
    app = QApplication(sys.argv)
    window = CompilerIDE()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main() 